package com.kpmg.datalake.schedule.utils.ftp;

import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Java Secure Channel
 *
 * @author Alex.zhao [alex.zhao@kpmg.com]
 * @since Created on azhao6 on 2018-08-13 15:36:39
 */
public class SftpClient {

  /**
   * linux 环境文件分隔符
   */
  public static final String LINUX_SEPARATOR = "/";
  private static final Logger logger = LoggerFactory.getLogger(SftpClient.class);
  private Session session = null;
  private ChannelSftp channel = null;

  private SftpClient() {
  }

  /**
   * 创建服务器连接
   *
   * @param host ip
   * @param port 端口
   * @param userName 用户名
   * @param password 密码
   * @param timeout 超时时间
   * @param aliveMax 最大存活
   * @return sftp 对象信息
   */
  public static SftpClient connect(String host, int port, String userName, String password,
      int timeout, int aliveMax) throws JSchException {
    return new SftpClient().init(host, port, userName, password, timeout, aliveMax);
  }

  private SftpClient init(String host, int port, String userName, String password, int timeout,
      int aliveMax) throws JSchException {
    Properties config = new Properties();

    // 创建JSch对象
    JSch jsch = new JSch();
    // 根据用户名，主机ip，端口获取一个Session对象
    session = jsch.getSession(userName, host, port);
    if (password != null) {
      // 设置密码
      session.setPassword(password);
    }
    config.put("userauth.gssapi-with-mic", "no");
    config.put("StrictHostKeyChecking", "no");
    // 为Session对象设置properties
    session.setConfig(config);
    // 设置timeout时间
    session.setTimeout(timeout);
    session.setServerAliveCountMax(aliveMax);
    // 通过Session建立链接
    session.connect();
    // 打开SFTP通道
    channel = (ChannelSftp) session.openChannel("sftp");
    // 建立SFTP通道的连接
    channel.connect();
    logger.info("SSH Channel connected.");
    return this;
  }

  /**
   * 释放链接
   */
  public void disconnect() {
    if (channel != null) {
      channel.disconnect();
    }
    if (session != null) {
      session.disconnect();
      logger.info("SSH Channel disconnected.");
    }
  }

  /**
   * 获取远程通道
   *
   * @return ChannelSftp
   */
  public ChannelSftp getChannel() {
    return channel;
  }

  /**
   * 发送文件
   */
  public void put(String src, String dst) throws SftpException {
    channel.put(src, dst, new FileProgressMonitor());
  }

  /**
   * 获取文件
   */
  public void get(String src, String dst) throws SftpException {
    channel.get(src, dst, new FileProgressMonitor());
  }


  /**
   * 批量下载文件
   *
   * @return List
   */
  public List<String> batchDownLoadFile(String remotePath, String localPath, boolean del)
      throws SftpException {
    List<String> filenames = new ArrayList<>();
    remotePath = remotePath.endsWith(SftpClient.LINUX_SEPARATOR) ? remotePath
        : remotePath + SftpClient.LINUX_SEPARATOR;
    localPath = localPath.endsWith(File.separator) ? localPath : localPath + File.separator;
    List<?> fileList = channel.ls(remotePath);
    if (CollectionUtils.isEmpty(fileList)) {
      return filenames;

    }
    for (Object jiaC : fileList) {
      ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) jiaC;
      String filename = entry.getFilename();
      SftpATTRS attrs = entry.getAttrs();
      //如果是目录递归下载
      if (attrs.isDir()) {
        //如果是父目录及当前目录跳出
        if (".".equals(filename) || "..".equals(filename)) {
          continue;
        }
        filenames.addAll(this.batchDownLoadFile(remotePath + entry.getFilename(),
            localPath + entry.getFilename(), del));
      } else {
        this.mkdirLocalPath(localPath);
        String localFileName = localPath + filename;
        String remoteFileName = remotePath + filename;
        channel.get(remoteFileName, localFileName, new FileProgressMonitor());
        filenames.add(localFileName);
        if (del) {
          channel.rm(remoteFileName);
        }
      }
    }

    logger.info("download file is success:remotePath={} and localPath={},file size is {} ",
        remotePath, localPath, fileList.size());
    return filenames;
  }

  /**
   * 校验并创建目录
   *
   * @param localPath 本地路径
   * @return Boolean
   */
  private Boolean mkdirLocalPath(String localPath) {
    File file = new File(localPath);
    if (!file.exists()) {
      return file.mkdirs();
    }
    return true;
  }

}
